Python | 更新Python后如何修复virtualenv

Author Avatar
Ricardo Liu 3月 12, 2018
  • 在其它设备中阅读本文章

摘要:在升级了Python后,由于Python路径变更,virtualenv中的symlinks将被破坏,本文提供了脚本来修复这个问题。

01. 运行环境和问题原因

在MBP上,我使用的是Homebrew安装的Python2和Python3,使用virtuanenvwrapper管理Python的虚拟环境(虚拟环境保存位置$WORKON_HOME=$HOME/.virtualenvs)。

当brew更新了Python后,再次进入虚拟环境并运行Python时会得到类似如下的错误:

dyld: Library not loaded: @executable_path/../.Python
  Referenced from: /your/home/.virtualenvs/virtualenv_name/bin/python
  Reason: image not found

执行ls -la ~/.virtualenvs/virtualenv_name/.Python会发现

/your/home/.virtualenvs/virtualenv_name/.Python -> /usr/local/Cellar/python@2/2.7.XX_X/Frameworks/Python.framework/Versions/2.7/Python

virtualenv崩溃的原因在于,由于symlinks的路径包含了版本号,更新之后会导致symlinks失效。

02. 解决办法

参考StackOverflow中的相关问题后,发现利用下面的语句可以修复virtuanenv中损坏的symlinks

find ~/.virtualenvs/virtualenv_name/ -type l -delete
virtualenv ~/.virtualenvs/virtualenv_name

或者

gfind ~/.virtualenvs/virtualenv_name/ -type l -xtype l -delete
virtualenv ~/.virtualenvs/virtualenv_name

不过,如果你有较多的虚拟环境,挨个更新就显得非常繁琐。更重要的问题是,如果你的虚拟环境中使用的Python版本既有Python2也有Python3,还有些虚拟环境包含了系统全局的packages,第二条语句就得加上参数-p pythonX--system-site-packages

为了彻底解决这个烦恼,尝试编写脚本来修复virtuanenv。为了判定如何重新创建虚拟环境,做了如下规定:

  • 在文件名的末尾通过23来区分虚拟环境中Python的版本(要求文件名中间不包含这两个数字),例如Jupyter2Jupyter3
  • 在文件名的末尾加上@来表示包含系统全局的packages,例如Jupyter2@

脚本的思路为:

  1. 执行virtualenvwrapper.sh(为了能够执行workon
  2. 执行workon来获得虚拟环境的列表
  3. 遍历每个虚拟环境
    1. 删除该环境中损坏的symlinks
    2. 根据虚拟环境的名称来确定virtualenv的参数
    3. 重新创建virtualenv

03. 脚本代码

脚本的代码如下,代码也可以在我的Github中查看。

#!/bin/bash
source virtualenvwrapper.sh
for env_name in $(workon); do
    echo ${env_name}
    env_path="${WORKON_HOME}/${env_name}"
    gfind ${env_path} -type l -xtype l -delete
    python_flag=""
    if [[ ${env_name} =~ "3" ]]; then
        python_flag="-p python3"
    else
        python_flag="-p python2"
    fi
    ssp_flag=""
    if [[ ${env_name} =~ "@" ]]; then
        ssp_flag="--system-site-packages"
    fi
    echo "virtualenv ${python_flag} ${ssp_flag} ${env_path}"
    virtualenv ${python_flag} ${ssp_flag} ${env_path}
done

04. 参考资料